package encrypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	mrand "math/rand"
)

const (
	aesCbcKey       = "9yXOowyd"
	internalKey     = "faa34f850a3ed41194c1ec7d381f86a4"
	fixedIdentifier = "U2hlbnpoZW4gT2NlYW53aW5nIFNtYXJ0IElubm92YXRpb25zIENvLiwgTHRk"
	randomSeed      = 10000
)

// AesEncryptDefault encryption using default key
func AesEncryptDefault(plainText string) (encryptTextStr string, err error) {
	return AesEncrypt(internalKey, plainText)
}

// AesEncrypt encryption using AES method, then encode using base64
func AesEncrypt(key, plainText string) (encryptTextStr string, err error) {
	var block cipher.Block
	if block, err = aes.NewCipher([]byte(key)); err != nil {
		return "", err
	}
	plainByte := []byte(plainText)
	encryptByte := make([]byte, aes.BlockSize+len(plainText))
	// initialization vector
	iv := encryptByte[:aes.BlockSize]
	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
		return
	}

	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(encryptByte[aes.BlockSize:], plainByte)
	encryptTextStr = Base64StdEncode(string(encryptByte))

	return
}

// AesDecryptDefault decryption using default key
func AesDecryptDefault(encryptText string) (plainText string, err error) {
	return AesDecrypt(internalKey, encryptText)
}

// AesDecrypt decryption using AES method
func AesDecrypt(key, encryptText string) (plainText string, err error) {
	var block cipher.Block
	var encryptByte []byte
	if block, err = aes.NewCipher([]byte(key)); err != nil {
		return
	}
	if encryptText, err = Base64StdDecode(encryptText); err != nil {
		return
	}
	encryptByte = []byte(encryptText)
	if len(encryptByte) < aes.BlockSize {
		err = errors.New("encryptText too short")
		return
	}

	iv := encryptByte[:aes.BlockSize]
	encryptByte = encryptByte[aes.BlockSize:]
	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(encryptByte, encryptByte)

	plainText = string(encryptByte)
	return
}

// BuildCipher 密钥规则是根据标识码获取对应值中的12个字符+随机的4个字符合成的16个字符；
// 对于配对类命令密钥取特定值，特定值取值规则：公司英文名：Shenzhen
// Oceanwing Smart Innovations Co., Ltd字符串进行BASE64，得到字符串：
// U2hlbnpoZW4gT2NlYW53aW5nIFNtYXJ0IElubm92YXRpb25zIENvLiwgTHRk
// 再以随机数%10作为起始位置从字符串中取12位+随机字符得到16个密钥字符
func BuildCipher() (ranNum int, ret string) {
	ranNum = mrand.Intn(randomSeed)
	ret = BuildCipherWithNum(ranNum)
	return
}

// BuildCipherWithNum 构造密钥
func BuildCipherWithNum(ranNum int) (ret string) {
	mod := ranNum % 10
	ret = fmt.Sprintf("%s%04d", fixedIdentifier[mod:mod+12], ranNum)
	return
}

// AesCbcDecrypt 解密JS登录密码
func AesCbcDecrypt(encryptText string) (ret string, err error) {
	var ciphertext []byte
	if ciphertext, err = base64Std.DecodeString(encryptText); err != nil {
		return
	}
	pkey := paddingLeft([]byte(aesCbcKey), '0', 16)
	var block cipher.Block
	if block, err = aes.NewCipher(pkey); err != nil {
		return
	}
	blockModel := cipher.NewCBCDecrypter(block, pkey)
	plantText := make([]byte, len(ciphertext))
	blockModel.CryptBlocks(plantText, ciphertext)
	plantText = pkcs7UnPadding(plantText, block.BlockSize())
	ret = string(plantText)
	return
}

func pkcs7UnPadding(plantText []byte, blockSize int) []byte {
	length := len(plantText)
	unpadding := int(plantText[length-1])
	return plantText[:(length - unpadding)]
}

func paddingLeft(ori []byte, pad byte, length int) []byte {
	if len(ori) >= length {
		return ori[:length]
	}
	pads := bytes.Repeat([]byte{pad}, length-len(ori))
	return append(pads, ori...)
}
